home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Networking / ARPSample / ARPerations.c next >
Encoding:
Text File  |  2000-09-28  |  21.0 KB  |  670 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        ARPerations.c
  3.  
  4.     Contains:    Standard high-level ARP operations.
  5.  
  6.     Written by: Quinn "The Eskimo!"    
  7.  
  8.     Copyright:    Copyright © 1997-1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                 7/21/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  20.                                             fixed output problem by changing '\r' to '\n'  
  21.                                             OSStatus ARPGetCacheReport(Handle cacheReport) 
  22.                 
  23.  
  24. */
  25. // Lots of standard OT constructs.
  26.  
  27. #include <OpenTransport.h>
  28. #include <OpenTptClient.h>
  29.  
  30. ///////////////////////////////////////////////////////////////////
  31. // Pick up the names of the standard OT modules.
  32.  
  33. #include <modnames.h>
  34.  
  35. ///////////////////////////////////////////////////////////////////
  36. // Pick up types and constants for I_STR ioctls.
  37.  
  38. #include <stropts.h>
  39.  
  40. ///////////////////////////////////////////////////////////////////
  41. // Pick up handle operations for ARPGetCacheReport.
  42.  
  43. #include <Memory.h>
  44.  
  45. ///////////////////////////////////////////////////////////////////
  46. // Standard C string operations.
  47.  
  48. #include <string.h>
  49.  
  50. ///////////////////////////////////////////////////////////////////
  51. // Constants and types for ARP module messages.
  52.  
  53. #include "OTARPModule.h"
  54.  
  55. ///////////////////////////////////////////////////////////////////
  56. // Our own prototypes.
  57.  
  58. #include "ARPerations.h"
  59.  
  60. ///////////////////////////////////////////////////////////////////
  61.  
  62. // The following equates are actually exported by <miioccom.h>, but
  63. //  they are commented out for some reason )-:  So instead of including
  64. //  <miioccom.h> we just define them again here.
  65.  
  66. #define MIOC_ND            'c'        /* ioctl's for Mentat's nd device */
  67.  
  68. // The following equates define the two "Name Dispatch" ioctls
  69. // for setting and getting OT internal parameters.
  70.  
  71. #define ND_GET            MIOC_CMD(MIOC_ND, 0)    /* Get a value */
  72. #define ND_SET            MIOC_CMD(MIOC_ND, 1)    /* Set a value */
  73.  
  74. // The name of the Name Dispatch variable you have to get in
  75. // order to get a dump of the ARP cache.
  76.  
  77. #define ARP_ND_CACHE_REPORT "arp_cache_report"
  78.  
  79. enum {
  80.     kARP_ND_CACHE_REPORT_Length = 17            // strlen(ARP_ND_CACHE_REPORT) + 1
  81. };
  82.  
  83. OSStatus ARPGetCacheReport(Handle cacheReport)
  84.     // See comment in header file.
  85. {
  86.     OSStatus err;
  87.     StreamRef arpStream;
  88.     struct strioctl nddIOCommand;
  89.     SInt32 i;
  90.     char ndCommandBuffer[kARP_ND_CACHE_REPORT_Length];
  91.     UInt32 realDataSize;
  92.     SInt8 cacheReportHandleState;
  93.     
  94.     // First open up a raw STREAMS connection to the ARP module.
  95.     
  96.     arpStream = OTStreamOpen(MI_ARP_NAME, 0, &err);
  97.     
  98.     if (err == noErr) {
  99.  
  100.         // Switch the stream in sync/blocking mode.  To make the
  101.         // code easier, we're going to do this synchronously.
  102.  
  103.         (void) OTStreamSetBlocking(arpStream);
  104.         (void) OTStreamSetSynchronous(arpStream);
  105.         
  106.         // Copy the name of the ND variable we're trying
  107.         // to get into our buffer.
  108.  
  109.         OTStrCopy(ndCommandBuffer, ARP_ND_CACHE_REPORT);
  110.     
  111.         // The ND_GET ioctl returns a value and sets ic_len.  A negative
  112.         //  value is an error and you can give up now (-:  The rule for
  113.         //  positive values is a bit weirder.  ic_len is always set
  114.         //  to the amount of data that is actually returned.  If the
  115.         //  data available exceeds the available buffer space (as
  116.         //  defined by the ic_len on input), the ioctl returns
  117.         //  a positive number that is the amount of buffer space
  118.         //  needed.  So we first call it with a minimal buffer
  119.         //  then give it the buffer space it requires.  Obviously
  120.         //  there's a concurrency race here, which we conveniently
  121.         //  ignore in this sample by return kEAGAINErr.
  122.  
  123.         // First get the size of data buffer we need to allocate by
  124.         // doing the ioctl with a small buffer and examining the result.
  125.         
  126.         nddIOCommand.ic_cmd = ND_GET;
  127.         nddIOCommand.ic_timout = 0;
  128.         nddIOCommand.ic_len = kARP_ND_CACHE_REPORT_Length;    // Length of ND name including...
  129.         nddIOCommand.ic_dp = ndCommandBuffer;                // ...the zero terminator.
  130.         
  131.         err = OTStreamIoctl(arpStream, I_STR, &nddIOCommand);
  132.  
  133.         if (err >= noErr) {
  134.  
  135.             if (err > noErr) {
  136.             
  137.                 // The first ioctl returned a positive number telling
  138.                 // us how big the data returned was.  We turn around
  139.                 // around make the ioctl again, this time passing
  140.                 // in an appropriately sized buffer.
  141.  
  142.                 realDataSize = err;
  143.                 SetHandleSize(cacheReport, realDataSize);
  144.                 err = MemError();
  145.                 
  146.                 if (err == noErr) {
  147.                     cacheReportHandleState = HGetState(cacheReport);
  148.                     HLock(cacheReport);
  149.                     
  150.                     OTStrCopy(*cacheReport, ARP_ND_CACHE_REPORT);
  151.  
  152.                     nddIOCommand.ic_cmd = ND_GET;
  153.                     nddIOCommand.ic_timout = 0;
  154.                     nddIOCommand.ic_len = realDataSize;
  155.                     nddIOCommand.ic_dp = *cacheReport;
  156.  
  157.                     err = OTStreamIoctl(arpStream, I_STR, &nddIOCommand);
  158.                     
  159.                     HSetState(cacheReport, cacheReportHandleState);
  160.                 }
  161.             }
  162.             
  163.             if (err == noErr) {
  164.             
  165.                 // Everything is cool, we have the ARP report.  Now
  166.                 // all we have remaining is a trivial format
  167.                 // conversion.  The format returned is straight
  168.                 // text with zero characters as the line terminator.
  169.                 // We mutate the line terminators into standard EOL '\n'
  170.                 
  171.                 for (i = 0; i < realDataSize; i++) {
  172.                     if ( (*cacheReport)[i] == '\0' ) {
  173.                         (*cacheReport)[i] = '\n';
  174.                     }
  175.                 }
  176.                 
  177.             } else {
  178.                 // Whoah, ARP table changed size!
  179.                 err = kEAGAINErr;
  180.             }
  181.         }
  182.     }
  183.     
  184.     // Clean up.
  185.     
  186.     if (arpStream != nil) {
  187.         (void) OTStreamClose(arpStream);
  188.     }
  189.     return (err);
  190. }
  191.  
  192. ///////////////////////////////////////////////////////////////////
  193.  
  194. // The following routines are used to copy variable length data structures
  195. // in the ARP command block that we're assembling.
  196.  
  197. static void CopyIntoCommandBuffer(char *buffer, UInt32 *currentOffset, void *data, UInt32 dataLength)
  198.     // Copy dataLength bytes from data into an ARP command buffer.
  199.     // buffer is a pointer to an ARP command block.
  200.     // currentOffset comes in as the number of bytes that are currently being
  201.     // used in the block, and is adjusted to represent the number of bytes we copied in.
  202.     // data is the address of the bytes to copy in.
  203.     // dataLength is the number of bytes to copy in.
  204. {
  205.     OTMemcpy(&buffer[*currentOffset], data, dataLength);
  206.     (*currentOffset) += dataLength;
  207. }
  208.  
  209. static void CopyInterfaceIntoCommandBuffer(char *buffer, UInt32 *currentOffset, char *interfaceName)
  210.     // Copy an interface name into an ARP command buffer.
  211.     // buffer is a pointer to an ARP command block.  This is assumed to point
  212.     // to at least an arc_t, although the other ARP command structures all
  213.     // begin with an arc_t, so it works for the other structures as well.
  214.     // currentOffset comes in as the number of bytes that are currently being
  215.     // used in the block, and is adjusted to represent the number of bytes we copied in.
  216.     // interfaceName is the address of a C string.
  217. {
  218.     arc_t *arpCommandPtr;
  219.     UInt32 interfaceNameLength;
  220.     
  221.     interfaceNameLength = OTStrLength(interfaceName) + 1;    // copy the string and the final null
  222.     arpCommandPtr = (arc_t *) buffer;
  223.     arpCommandPtr->arc_name_offset = *currentOffset;
  224.     arpCommandPtr->arc_name_length = interfaceNameLength;
  225.     CopyIntoCommandBuffer(buffer, currentOffset, interfaceName, interfaceNameLength);
  226. }
  227.  
  228. static void CopyProtoIntoCommandBuffer(char *buffer, UInt32 *currentOffset,
  229.                                         void *protoAddress, UInt32 protoSize)
  230.     // Copy an protocol address into an ARP command buffer.
  231.     // buffer is a pointer to an ARP command block.  This is assumed to point
  232.     // to at least an arc_t, although the other ARP command structures all
  233.     // begin with an arc_t, so it works for the other structures as well.
  234.     // currentOffset comes in as the number of bytes that are currently being
  235.     // used in the block, and is adjusted to represent the number of bytes we copied in.
  236.     // protoAddress is the address of the bytes of the protocol address to copy in.
  237.     // protoSize is the number of bytes to copy in.
  238. {
  239.     arc_t *arpCommandPtr;
  240.     
  241.     arpCommandPtr = (arc_t *) buffer;
  242.     arpCommandPtr->arc_proto_addr_offset = *currentOffset;
  243.     arpCommandPtr->arc_proto_addr_length = protoSize;
  244.     CopyIntoCommandBuffer(buffer, currentOffset, protoAddress, protoSize);
  245. }
  246.  
  247. ///////////////////////////////////////////////////////////////////
  248.  
  249. OSStatus ARPAddEntry(char *interfaceName,
  250.                         UInt32 arpProto,
  251.                         UInt32 flags,
  252.                         void *protoAddress, UInt32 protoSize, void *protoMask,
  253.                         void *hardwareAddress, UInt32 hardwareSize)
  254.     // See comment in header file.
  255. {
  256.     OSStatus err;
  257.     StreamRef arpStream;
  258.     char arpCommandBuffer[256];
  259.     area_t *arpAddCommandPtr;
  260.     UInt32 currentOffset;
  261.     struct strioctl arpIOControl;
  262.  
  263.     // First up, open a simple stream to the ARP as a driver.
  264.  
  265.     arpStream = OTStreamOpen(MI_ARP_NAME, 0, &err);
  266.     
  267.     if (err == noErr) {
  268.         (void) OTStreamSetBlocking(arpStream);
  269.         (void) OTStreamSetSynchronous(arpStream);
  270.  
  271.         // Initialise the command buffer for this command.
  272.  
  273.         arpAddCommandPtr = (area_t *) &arpCommandBuffer[0];
  274.         currentOffset = sizeof(area_t);
  275.  
  276.         arpAddCommandPtr->area_arc.arc_cmd = AR_ENTRY_ADD;
  277.         
  278.         CopyInterfaceIntoCommandBuffer(arpCommandBuffer, ¤tOffset, interfaceName);
  279.             
  280.         arpAddCommandPtr->area_arc.arc_proto = arpProto;
  281.         
  282.         CopyProtoIntoCommandBuffer(arpCommandBuffer, ¤tOffset, protoAddress, protoSize);
  283.  
  284.         arpAddCommandPtr->area_arc.arc_flags = flags;
  285.         arpAddCommandPtr->area_arc.arc_client_q = nil;    // ignored by ARP for this command
  286.  
  287.         arpAddCommandPtr->area_proto_mask_offset = currentOffset;
  288.         CopyIntoCommandBuffer(arpCommandBuffer, ¤tOffset, protoMask, protoSize);
  289.         
  290.         arpAddCommandPtr->area_hw_addr_offset = currentOffset;
  291.         arpAddCommandPtr->area_hw_addr_length = hardwareSize;
  292.         CopyIntoCommandBuffer(arpCommandBuffer, ¤tOffset, hardwareAddress, hardwareSize);
  293.  
  294.         // Initialise the I_STR ioctl structure.
  295.  
  296.         arpIOControl.ic_cmd = AR_ENTRY_ADD;
  297.         arpIOControl.ic_timout = 0;
  298.         arpIOControl.ic_len = currentOffset;
  299.         arpIOControl.ic_dp = &arpCommandBuffer[0];
  300.         
  301.         // Send the ioctl.
  302.  
  303.         err = OTStreamIoctl(arpStream, I_STR, &arpIOControl);
  304.     }
  305.  
  306.     // Clean up.
  307.     
  308.     if (arpStream != nil) {
  309.         (void) OTStreamClose(arpStream);
  310.     }
  311.     return (err);
  312. }
  313.  
  314. ///////////////////////////////////////////////////////////////////
  315.  
  316. OSStatus ARPDeleteEntry(char *interfaceName,
  317.                         UInt32 arpProto,
  318.                         void *protoAddress, UInt32 protoSize)
  319.     // See comment in header file.
  320. {
  321.     OSStatus err;
  322.     StreamRef arpStream;
  323.     char arpCommandBuffer[256];
  324.     arc_t *arpDeleteCommandPtr;
  325.     UInt32 currentOffset;
  326.     struct strioctl arpIOControl;
  327.  
  328.     // First up, open a simple stream to the ARP as a driver.
  329.  
  330.     arpStream = OTStreamOpen(MI_ARP_NAME, 0, &err);
  331.     
  332.     if (err == noErr) {
  333.         (void) OTStreamSetBlocking(arpStream);
  334.         (void) OTStreamSetSynchronous(arpStream);
  335.  
  336.         // Initialise the command buffer for this command.
  337.  
  338.         arpDeleteCommandPtr = (arc_t *) &arpCommandBuffer[0];
  339.         currentOffset = sizeof(arc_t);
  340.  
  341.         arpDeleteCommandPtr->arc_cmd = AR_ENTRY_DELETE;
  342.         
  343.         CopyInterfaceIntoCommandBuffer(arpCommandBuffer, ¤tOffset, interfaceName);
  344.             
  345.         arpDeleteCommandPtr->arc_proto = arpProto;
  346.         
  347.         CopyProtoIntoCommandBuffer(arpCommandBuffer, ¤tOffset, protoAddress, protoSize);
  348.  
  349.         arpDeleteCommandPtr->arc_flags = 0;            // ignored by ARP for this command
  350.         arpDeleteCommandPtr->arc_client_q = nil;    // ignored by ARP for this command
  351.  
  352.         // Initialise the I_STR ioctl structure.
  353.  
  354.         arpIOControl.ic_cmd = AR_ENTRY_DELETE;
  355.         arpIOControl.ic_timout = 0;
  356.         arpIOControl.ic_len = currentOffset;
  357.         arpIOControl.ic_dp = &arpCommandBuffer[0];
  358.         
  359.         // Send the ioctl.
  360.  
  361.         err = OTStreamIoctl(arpStream, I_STR, &arpIOControl);
  362.     }
  363.  
  364.     // Clean up.
  365.     
  366.     if (arpStream != nil) {
  367.         (void) OTStreamClose(arpStream);
  368.     }
  369.     return (err);
  370. }
  371.  
  372. ///////////////////////////////////////////////////////////////////
  373.  
  374. OSStatus ARPCacheQuery(char *interfaceName,
  375.                         UInt32 arpProto,
  376.                         void *protoAddress, UInt32 protoSize,
  377.                         void *hardwareAddress, UInt32 hardwareSize, UInt32 *flags)
  378.     // See comment in header file.
  379. {
  380.     OSStatus err;
  381.     StreamRef arpStream;
  382.     char arpCommandBuffer[256];
  383.     area_t *arpQueryCommandPtr;
  384.     UInt32 currentOffset;
  385.     struct strioctl arpIOControl;
  386.     
  387.     // First up, open a simple stream to the ARP as a driver.
  388.     
  389.     arpStream = OTStreamOpen(MI_ARP_NAME, 0, &err);
  390.     
  391.     if (err == noErr) {
  392.         (void) OTStreamSetBlocking(arpStream);
  393.         (void) OTStreamSetSynchronous(arpStream);
  394.  
  395.         // Initialise the command buffer for this command.
  396.  
  397.         arpQueryCommandPtr = (area_t *) &arpCommandBuffer[0];
  398.         currentOffset = sizeof(area_t);
  399.  
  400.         arpQueryCommandPtr->area_arc.arc_cmd = AR_ENTRY_SQUERY;
  401.         
  402.         CopyInterfaceIntoCommandBuffer(arpCommandBuffer, ¤tOffset, interfaceName);
  403.             
  404.         arpQueryCommandPtr->area_arc.arc_proto = arpProto;
  405.         
  406.         CopyProtoIntoCommandBuffer(arpCommandBuffer, ¤tOffset, protoAddress, protoSize);
  407.  
  408.         arpQueryCommandPtr->area_arc.arc_flags = 0;            // return value
  409.         arpQueryCommandPtr->area_arc.arc_client_q = nil;    // ignored by ARP for this command
  410.  
  411.         arpQueryCommandPtr->area_proto_mask_offset = 0;        // ignored by ARP for this command
  412.         
  413.         arpQueryCommandPtr->area_hw_addr_offset = currentOffset;
  414.         arpQueryCommandPtr->area_hw_addr_length = hardwareSize;
  415.         currentOffset += hardwareSize;                        // space for return value
  416.  
  417.         // Initialise the I_STR ioctl structure.
  418.  
  419.         arpIOControl.ic_cmd = AR_ENTRY_SQUERY;
  420.         arpIOControl.ic_timout = 0;
  421.         arpIOControl.ic_len = currentOffset;
  422.         arpIOControl.ic_dp = &arpCommandBuffer[0];
  423.         
  424.         // Send the ioctl.
  425.         
  426.         err = OTStreamIoctl(arpStream, I_STR, &arpIOControl);
  427.     }
  428.     if (err == noErr) {
  429.  
  430.         // Copy results out to client buffer.
  431.         
  432.         OTMemcpy( hardwareAddress,                                                    // dest
  433.                     &arpCommandBuffer[arpQueryCommandPtr->area_hw_addr_offset],        // source
  434.                     hardwareSize);                                                    // length
  435.         *flags = arpQueryCommandPtr->area_arc.arc_flags;
  436.     }
  437.     
  438.     // Clean up.
  439.     
  440.     if (arpStream != nil) {
  441.         (void) OTStreamClose(arpStream);
  442.     }
  443.     return (err);
  444. }
  445.  
  446. ///////////////////////////////////////////////////////////////////
  447.  
  448. // The ARPInterfaceInfo structure is used to record all the information this
  449. // module stores about an interface that it brings up.  When
  450. // you call ARPInterfaceUp, the interfaceCookie result is really
  451. // a pointer to one of these structures.
  452.  
  453. struct ARPInterfaceInfo {
  454.     StreamRef interfaceStream;        // The ARP stream for the interface.
  455.     char interfaceName[256];        // The interface name, as calculated by GetARPInterfaceName.
  456. };
  457. typedef struct ARPInterfaceInfo ARPInterfaceInfo, *ARPInterfaceInfoPtr;
  458.  
  459. static OSStatus GetARPInterfaceName(ARPInterfaceInfoPtr interfaceInfo)
  460.     // Get the name for an interface on which we're about to bring up
  461.     // ARP.  ARP forms the interface name by taking the name of the module
  462.     // and appending a number, starting at 0, to make it unique.  Unfortunately
  463.     // we have no way of determining which interfaces are already in use
  464.     // by ARP, so we can't tell what number it will assign.  Therefore
  465.     // this sample just takes a guess, assuming 0.
  466.     // The routine gets the name of the module using the I_LIST ioctl,
  467.     // which returns a list of the module names on a stream, and looking
  468.     // for the last module name in the stream, ie the driver.  There
  469.     // really shouldn't be more than one module in the stream, so the
  470.     // array of 10 str_mlist we allocate for the return result should be
  471.     // more than enough.
  472. {
  473.     OSStatus err;
  474.     struct str_list streamList;
  475.     struct str_mlist streamListNames[10];
  476.     
  477.     streamList.sl_nmods = 10;
  478.     streamList.sl_modlist = streamListNames;
  479.     err = OTStreamIoctl(interfaceInfo->interfaceStream, I_LIST, &streamList);
  480.     if (err >= noErr) {
  481.         if ( streamList.sl_nmods == 0 ) {
  482.             err = -5;
  483.         } else {
  484.             OTStrCopy(interfaceInfo->interfaceName, streamListNames[ streamList.sl_nmods-1 ].l_name );
  485.             OTStrCat(interfaceInfo->interfaceName, "0");
  486.         }
  487.     }
  488.     
  489.     return (err);
  490. }
  491.  
  492. static OSStatus SendARPInterfaceUpDown(ARPInterfaceInfoPtr interfaceInfo, UInt32 arpCommand)
  493.     // Send an AR_INTERFACE_UP or AR_INTERFACE_DOWN command to the
  494.     // ARP interface we just created.  The name of the interface
  495.     // and the controlling stream for the interface are contained
  496.     // in the interfaceInfo pointer.  arpCommand is the actual
  497.     // command to send, ie either AR_INTERFACE_UP or AR_INTERFACE_DOWN.
  498. {
  499.     OSStatus err;
  500.     char arpCommandBuffer[256];
  501.     arc_t *arpCommandPtr;
  502.     UInt32 currentOffset;
  503.     struct strioctl arpIOControl;
  504.     
  505.     // Initialise the command buffer for this command.
  506.     
  507.     arpCommandPtr = (arc_t *) &arpCommandBuffer[0];
  508.     currentOffset = sizeof(arc_t);
  509.  
  510.     arpCommandPtr->arc_cmd = arpCommand;
  511.     
  512.     CopyInterfaceIntoCommandBuffer(arpCommandBuffer, ¤tOffset, interfaceInfo->interfaceName);
  513.         
  514.     arpCommandPtr->arc_proto = 0;                // ignored by ARP for this command
  515.     
  516.     arpCommandPtr->arc_proto_addr_offset = 0;    // ignored by ARP for this command
  517.     arpCommandPtr->arc_proto_addr_length = 0;    // ignored by ARP for this command
  518.  
  519.     arpCommandPtr->arc_flags = 0;                // ignored by ARP for this command
  520.     arpCommandPtr->arc_client_q = nil;            // ignored by ARP for this command
  521.  
  522.     // Initialise the I_STR ioctl structure.
  523.  
  524.     arpIOControl.ic_cmd = arpCommand;
  525.     arpIOControl.ic_timout = 0;
  526.     arpIOControl.ic_len = currentOffset;
  527.     arpIOControl.ic_dp = &arpCommandBuffer[0];
  528.     
  529.     // Send the ioctl.
  530.     
  531.     err = OTStreamIoctl(interfaceInfo->interfaceStream, I_STR, &arpIOControl);
  532.     
  533.     return (err);
  534. }
  535.  
  536. OSStatus ARPInterfaceUp(char *configString, UInt32 *interfaceCookie)
  537.     // See comment in header file.
  538. {
  539.     OSStatus err;
  540.     ARPInterfaceInfoPtr interfaceInfo;
  541.     OTConfiguration *arpConfig;
  542.     
  543.     // Prepare for failure.
  544.     
  545.     arpConfig = nil;
  546.     
  547.     // Create a record which we use to hold all the information
  548.     // about this interface.  The address of this record is passed
  549.     // back to the client as the interfaceCookie.
  550.     
  551.     err = noErr;
  552.     interfaceInfo = (ARPInterfaceInfoPtr) OTAllocMem(sizeof(ARPInterfaceInfo));
  553.     if ( interfaceInfo == nil) {
  554.         err = kENOMEMErr;
  555.     } else {
  556.         OTMemzero(interfaceInfo, sizeof(ARPInterfaceInfo));
  557.     }
  558.     
  559.     // Now create a configuration from the supplied configString...
  560.     
  561.     if (err == noErr) {
  562.         arpConfig = OTCreateConfiguration(configString);
  563.         if (arpConfig == kOTNoMemoryConfigurationPtr) {
  564.             err = kENOMEMErr;
  565.         } else if (arpConfig == kOTInvalidConfigurationPtr) {
  566.             err = kENXIOErr;
  567.         }
  568.     }
  569.  
  570.     // ... and push the ARP module on top of this configuration.
  571.     // Don't ask me why you have to do this or I'll start to
  572.     // whimper.
  573.     
  574.     if (err == noErr) {
  575.         (void) OTCfigPushParent(arpConfig, MI_ARPM_NAME, &err);
  576.     }
  577.     
  578.     // Now create a stream to device driver over which we'll
  579.     // be running ARP.  Note the use OTCreateStream rather than
  580.     // OTStreamOpen.  This is because the device driver might
  581.     // have extra plumbing underneath it (eg an ATM LANE emulation
  582.     // driver running over an ATM hardware driver), and just
  583.     // opening the driver would not give the driver's configurator
  584.     // chance to set up this plumbing.
  585.     
  586.     if (err == noErr) {
  587.         interfaceInfo->interfaceStream = OTCreateStream(arpConfig, 0, &err);
  588.         if (err != noErr) {
  589.             // Most OT create/open routines seem to return nil if they fail
  590.             // with an error, however it seems that OTCreateSteam is not
  591.             // as friendly.  So if we get an error we nil out our record
  592.             // of the stream to avoid trying to OTStreamClose a bogus stream
  593.             // as we clean up.
  594.             interfaceInfo->interfaceStream = nil;
  595.         }
  596.         arpConfig = nil;
  597.     }
  598.     
  599.     // Get the name of the interface that ARP will create when
  600.     // we start running it over our newly created stream.
  601.  
  602.     if (err == noErr) {
  603.         (void) OTStreamSetBlocking(interfaceInfo->interfaceStream);
  604.         (void) OTStreamSetSynchronous(interfaceInfo->interfaceStream);
  605.         err = GetARPInterfaceName(interfaceInfo);
  606.     }
  607.     
  608.     // Push ARP on top of the driver stream and then tell it that
  609.     // the corresponding interface is up.  ARP will then consider
  610.     // the interface to be active.  It will snarf ARP responses
  611.     // as they go across the network, and you can use the
  612.     // cache query, add and remove commands on that interface.
  613.     
  614.     if (err == noErr) {
  615.         err = OTStreamIoctl(interfaceInfo->interfaceStream, I_PUSH, MI_ARPM_NAME);
  616.     }
  617.     if (err == noErr) {
  618.         err = SendARPInterfaceUpDown(interfaceInfo, AR_INTERFACE_UP);
  619.     }
  620.     
  621.     // Clean up after failure.
  622.     
  623.     if (err != noErr) {
  624.         if (interfaceInfo != nil) {
  625.             if ( interfaceInfo->interfaceStream != nil ) {
  626.                 OTStreamClose( interfaceInfo->interfaceStream );
  627.             }
  628.             OTFreeMem(interfaceInfo);
  629.             interfaceInfo = nil;
  630.         }
  631.     }
  632.     
  633.     // General clean up.
  634.     
  635.     if (arpConfig != nil) {
  636.         OTDestroyConfiguration(arpConfig);
  637.     }
  638.     
  639.     // Regardless of error result, copy interfaceInfo out to client buffer.
  640.     // This ensures that the client gets a nil cookie when we get an error.
  641.     
  642.     *interfaceCookie = (UInt32) interfaceInfo;
  643.  
  644.     return (err);
  645. }
  646.  
  647. ///////////////////////////////////////////////////////////////////
  648.  
  649. OSStatus ARPInterfaceDown(UInt32 interfaceCookie)
  650.     // See comment in header file.
  651. {
  652.     OSStatus err;
  653.     ARPInterfaceInfoPtr interfaceInfo;
  654.     
  655.     interfaceInfo = (ARPInterfaceInfoPtr) interfaceCookie;
  656.     
  657.     // First tell ARP we're about to bring the interface down.
  658.     
  659.     err = SendARPInterfaceUpDown(interfaceInfo, AR_INTERFACE_DOWN);
  660.     
  661.     // Now close the stream that we opened to run the interface
  662.     // over.
  663.     if (err == noErr) {
  664.         (void) OTStreamClose( interfaceInfo->interfaceStream );
  665.         OTFreeMem(interfaceInfo);
  666.     }
  667.     
  668.     return (err);
  669. }
  670.